package com.jhf.youke.stock.domain.model.Do;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.jhf.youke.core.ddd.BaseDoEntity;
import com.jhf.youke.core.utils.StringUtils;
import com.jhf.youke.stock.domain.exception.StockException;
import com.jhf.youke.stock.domain.model.dto.OutboundDto;
import com.jhf.youke.stock.domain.model.dto.OutboundListDto;
import lombok.Data;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author  RHJ
 **/

@Data
public class StockDo extends BaseDoEntity {

    private static final long serialVersionUID = -87183740247767778L;

    private static final String COMM_CHECK = "comm";
    private static final String SPECS_CHECK = "specs";

    /**
     * 产品ID
     */
    private Long productId;

    /**
     * 产品名
     */
    private String productName;

    /**
     * 单位标识
     */
    private Long companyId;

    /**
     * 单位名
     */
    private String companyName;

    /**
     * 仓库标识
     */
    private Long warehouseId;

    /**
     * 入库数量
     */
    private BigDecimal inNum;

    /**
     * 出库数量
     */
    private BigDecimal outNum;

    /**
     * 库存数量
     */
    private BigDecimal whNum;

    /**
     * 预占数量
     */
    private BigDecimal preNum;

    /**
     * 可用数量
     */
    private BigDecimal num;

    /**
     *  本次扣减数量
     * */
    private BigDecimal actNum;

    /**
     * 成本价
     */
    private BigDecimal costPrice;

    /**
     * 销售价
     */
    private BigDecimal price;

    /**
     * 入库金额
     */
    private BigDecimal inFee;

    /**
     * 出库金额
     */
    private BigDecimal outFee;

    /**
     * 规格型号
     */
    private String specs;

    /**
     * 计量单位
     */
    private String unitName;

    /**
     * 库存金额
     */
    private BigDecimal fee;

    private List<Long> productIds;

    private List<StockDo> stockDoList;

    /**
    * 出库类型 1 先进先出 2 按库存出库
    */
    private Integer outType ;

    private Long bizId;

    public StockDo(){

    }


    public StockDo(OutboundDto outboundDto){
         this.outType = outboundDto.getOutType();
         this.warehouseId = outboundDto.getWarehouseId();
         this.companyId = outboundDto.getCompanyId();
         this.bizId = outboundDto.getId();
         List<StockDo> stockDoList = new ArrayList<>();
         for(OutboundListDto list : outboundDto.getOutboundListDoList()){
             StockDo stockDo = new StockDo();
             stockDo.setId(list.getStockId());
             stockDo.setProductId(list.getProductId());
             stockDo.setSpecs(list.getSpecs());
             stockDo.setNum(list.getNum());
             stockDoList.add(stockDo);
         }
         this.stockDoList = stockDoList;
    }


    public <T> T requireNonNull(T obj, Object column, String errorMessage) {
        if (Objects.isNull(column)) {
            throw new StockException(errorMessage);
        }
        return obj;
    }

    private StockDo validateNull(StockDo stockDo){
          //可使用链式法则进行为空检查
          stockDo.
          requireNonNull(stockDo, stockDo.getRemark(),"不能为NULL");
                
        return stockDo;
    }



    /**
    * @Description:  先进先出根据产品ID，规格进行汇总
    * @Param: [stockList]
    * @return: java.util.Map<java.lang.String,java.lang.Integer>
    * @Author: RHJ
    * @Date: 2023/6/23
    */
    public Map<String, Map<String, BigDecimal>> sumStock() {

      Map<String, BigDecimal> specsMap = new HashMap<>(64);
      Map<String, BigDecimal> resultMap = new HashMap<>(64);
      Map<String, Map<String, BigDecimal>> map = new HashMap<>(8);
      Map<String, BigDecimal> productMap = new HashMap<>(64);
      for (StockDo stock : this.stockDoList) {
        String key = "";
        BigDecimal num = BigDecimal.ZERO;
        productMap.put(stock.getProductId().toString(), num);
        if (StringUtils.isNotBlank(stock.getSpecs())) {
            key = stock.getProductId()+"_"+stock.getSpecs();
            num = specsMap.containsKey(key) ? stock.getNum().add(specsMap.get(key)) : stock.getNum();
            specsMap.put(key, num);
        } else {
            key = stock.getProductId().toString();
            num = specsMap.containsKey(key) ? stock.getNum().add(specsMap.get(key)) : stock.getNum();
            resultMap.put(key, num);
        }

      }
      map.put("A", specsMap);
      map.put("B", resultMap);
      map.put("C", productMap);
      return map;
    }

    /**
    * @Description:  带规格的库存检查
    * @Param: [specsMap, stockDoList]
    * @return: 返加库存的预占更新, 冻结表的预占
    * @Author: RHJ
    * @Date: 2023/6/26
    */
//    public List<StockDo> specsCheckNum(Map<String,BigDecimal> specsMap, List<StockDo> stockDoList)throws StockException{
//
//        Multimap<String, StockDo> stockMap = getStockMap(stockDoList);
//        List<StockDo> result_list = new ArrayList<>();
//
//        for (Map.Entry<String, BigDecimal> entry : specsMap.entrySet()){
//            String key = entry.getKey();
//            String[] product = key.split("_");
//            Long productId = StringUtils.toLong(product[0]);
//            String specs = product[1];
//            BigDecimal num =  entry.getValue();
//            List<StockDo> stockList = (List<StockDo>) stockMap.get(productId+"_"+specs);
//            if(stockList != null && !stockList.isEmpty()){
//                for(int i =0; i< stockList.size(); i++){
//                    StockDo stock = stockList.get(i);
//                    // 如果需求数量小于库存数量结束
//                    if(num.compareTo(stock.getNum()) <= 0){
//                        stock.setNum(stock.getNum().subtract(num));
//                        stock.setPreNum(stock.getPreNum().add(num));
//                        result_list.add(stock);
//                        System.out.println("数量充足预占：" + stock.getId() +" 产品："+ stock.getProductId()
//                                +" 规格:" + stock.getSpecs() + " 数量:" + num);
//                        continue;
//                    }else{
//                        // 如果是最后一条,则数量不足
//                        if(i == stockList.size()- 1){
//                            throw new StockException("库存："+ productId + "数量不足");
//                        }else{ // 不是最后一条，则扣掉当前库存，继续下一条扣减
//                            num = num.subtract(stock.getNum());
//                            BigDecimal old_num = stock.getNum();
//                            stock.setNum(BigDecimal.ZERO);
//                            stock.setPreNum(stock.getWhNum());
//                            result_list.add(stock);
//                            System.out.println("数量不足预占：" + stock.getId() +" 产品："+ stock.getProductId()
//                            +" 规格:" + stock.getSpecs() + " 数量:" + old_num);
//                        }
//                    }
//                }
//            }else{
//                throw new StockException("没有库存："+ productId);
//            }
//        }
//        return result_list;
//    }

    /**
     * @Description:  不带规格的库存检查
     * @Param: [specsMap, stockDoList]
     * @return: 返加库存的预占更新, 冻结表的预占
     * @Author: RHJ
     * @Date: 2023/6/26
     */
//    public List<StockDo> commCheckNum(Map<String,BigDecimal> specsMap, List<StockDo> stockDoList)throws StockException{
//
//        Multimap<String, StockDo> stockMap = getStockMap(stockDoList);
//        List<StockDo> result_list = new ArrayList<>();
//
//        for (Map.Entry<String, BigDecimal> entry : specsMap.entrySet()){
//            String productId = entry.getKey();
//            BigDecimal num =  entry.getValue();
//            List<StockDo> stockList = (List<StockDo>) stockMap.get(productId);
//            if(stockList != null && !stockList.isEmpty()){
//                for(int i =0; i< stockList.size(); i++){
//                    StockDo stock = stockList.get(i);
//                    // 如果需求数量小于库存数量结束
//                    if(num.compareTo(stock.getNum()) <= 0){
//                        stock.setNum(stock.getNum().subtract(num));
//                        stock.setPreNum(stock.getPreNum().add(num));
//                        result_list.add(stock);
//                        System.out.println("数量充足预占：" + stock.getId() +" 产品："+ stock.getProductId()
//                                +" 规格:" + stock.getSpecs() + " 数量:" + num);
//                        continue;
//                    }else{
//                        // 如果是最后一条,则数量不足
//                        if(i == stockList.size()- 1){
//                            throw new StockException("库存："+ productId + "数量不足");
//                        }else{ // 不是最后一条，则扣掉当前库存，继续下一条扣减
//                            num = num.subtract(stock.getNum());
//                            BigDecimal old_num = stock.getNum();
//                            stock.setNum(BigDecimal.ZERO);
//                            stock.setPreNum(stock.getWhNum());
//                            result_list.add(stock);
//                            System.out.println("数量不足预占：" + stock.getId() +" 产品："+ stock.getProductId()
//                                    +" 规格:" + stock.getSpecs() + " 数量:" + old_num);
//                        }
//                    }
//                }
//            }else{
//                throw new StockException("没有库存："+ productId);
//            }
//        }
//        return result_list;
//    }

//    public  Multimap<String, StockDo> getStockMap(List<StockDo> stockDoList){
//        Multimap<String, StockDo> stockMap = ArrayListMultimap.create();
//        for(StockDo stockDo : stockDoList){
//            stockMap.put(stockDo.getProductId()+"_"+stockDo.getSpecs(), stockDo);
//        }
//        return stockMap;
//    }



    public List<StockDo> specsCheckNum(Map<String,BigDecimal> specsMap, List<StockDo> stockDoList) throws StockException {
        return checkNum(specsMap, stockDoList, SPECS_CHECK);
    }

    public List<StockDo> commCheckNum(Map<String,BigDecimal> commMap, List<StockDo> stockDoList) throws StockException {
        return checkNum(commMap, stockDoList, COMM_CHECK);
    }

    /** 
    * @Description:  根据汇总的需求，进行库存检查
    * @Param: [map, stockDoList, checkType] 
    * @return: java.util.List<com.jhf.youke.stock.domain.model.Do.StockDo> 
    * @Author: RHJ
    * @Date: 2023/6/27 
    */     
    private List<StockDo> checkNum(Map<String,BigDecimal> map, List<StockDo> stockDoList, String checkType) throws StockException {
        Multimap<String, StockDo> stockMap = getStockMap(stockDoList);
        List<StockDo> result_list = new ArrayList<>();

        for (Map.Entry<String, BigDecimal> entry : map.entrySet()){
            String key = entry.getKey();
            Long productId;
            String specs;
            if (COMM_CHECK.equals(checkType)) {
                productId = StringUtils.toLong(key);
                specs = null;
            } else {
                String[] product = key.split("_");
                productId = StringUtils.toLong(product[0]);
                specs = product[1];
            }

            BigDecimal num =  entry.getValue();
            List<StockDo> stockList = getStockList(stockMap, productId, specs);
            if(stockList != null && !stockList.isEmpty()){
                for(int i =0; i< stockList.size(); i++){
                    StockDo stock = stockList.get(i);
                    // 如果需求数量小于库存数量结束
                    if(num.compareTo(stock.getNum()) <= 0){
                        stock.setNum(stock.getNum().subtract(num));
                        stock.setPreNum(stock.getPreNum().add(num));
                        stock.setActNum(num);
                        result_list.add(stock);
                        System.out.println("数量充足预占：" + stock.getId() +" 产品："+ stock.getProductId()
                                +" 规格:" + stock.getSpecs() + " 数量:" + num);
                        continue;
                    }else{
                        // 如果是最后一条,则数量不足
                        if(i == stockList.size()- 1){
                            throw new StockException("库存："+ productId + "数量不足");
                        }else{ // 不是最后一条，则扣掉当前库存，继续下一条扣减
                            num = num.subtract(stock.getNum());
                            BigDecimal old_num = stock.getNum();
                            stock.setNum(BigDecimal.ZERO);
                            stock.setPreNum(stock.getWhNum());
                            stock.setActNum(old_num);
                            result_list.add(stock);
                            System.out.println("数量不足预占：" + stock.getId() +" 产品："+ stock.getProductId()
                                    +" 规格:" + stock.getSpecs() + " 数量:" + old_num);
                        }
                    }
                }
            }else{
                throw new StockException("没有库存："+ productId);
            }
            System.out.println("实际库存");
            System.out.println(stockList);
        }

        System.out.println("预占明细");
        System.out.println(result_list);
        updateActStock(result_list, stockDoList);
        return result_list;
    }
    
    /** 
    * @Description: 1. 将库存转map,进行核减,处理完成再将map转为list 
    * @Param: [pre_list, stock_list] 
    * @return: java.util.List<com.jhf.youke.stock.domain.model.Do.StockDo> 
    * @Author: RHJ
    * @Date: 2023/6/27 
    */
    private List<StockDo> updateActStock(List<StockDo> pre_list, List<StockDo> stock_list){

        Map<Long, StockDo> stockMap = stock_list.stream()
                .collect(Collectors.toMap(StockDo::getId, stockDo -> stockDo));

        for (StockDo s : pre_list) {
            StockDo stock = stockMap.get(s.getId());
            if (stock != null) {
                stock.setNum(s.getNum());
                stock.setPreNum(s.getPreNum());
                stockMap.put(s.getId(),stock);
            }
        }
        List<StockDo> stockList = new ArrayList<>(stockMap.values());
        return stockList;
    }
    

    private List<StockDo> getStockList(Multimap<String, StockDo> stockMap, Long productId, String specs) {
        if (specs == null) {
            return (List<StockDo>) stockMap.get(String.valueOf(productId));
        } else {
            return (List<StockDo>) stockMap.get(productId + "_" + specs);
        }
    }

    private Multimap<String, StockDo> getStockMap(List<StockDo> stockDoList) {
        Multimap<String, StockDo> stockMap = ArrayListMultimap.create();
        for (StockDo stock : stockDoList) {
            if(StringUtils.isNotBlank(stock.getSpecs())){
                stockMap.put(stock.getProductId() + "_" + stock.getSpecs(), stock);
            }else{
                stockMap.put(stock.getProductId().toString(), stock);
            }

        }
        return stockMap;
    }



}


